﻿using System;
using System.Linq.Expressions;

namespace Commons.Diagnostics
{
    public static class Debug
    {
        public static class Assert
        {
            public static void NotNull<T>( Expression<Func<T>> aExpression )
            {
#if DEBUG
                MemberExpression lBody = ( (MemberExpression)aExpression.Body );
                System.Diagnostics.Debug.Assert(
                    ( (ConstantExpression)lBody.Expression ).Value != null,
                    string.Format( "{0} não pode ser nulo.", lBody.Member.Name )
                );
#endif
            }

            public static void NotNullOrEmpty<T>( Expression<Func<T>> aExpression )
            {
#if DEBUG
                MemberExpression lBody = ( (MemberExpression)aExpression.Body );
                //Referência: http://blogs.msdn.com/b/csharpfaq/archive/2010/03/11/how-can-i-get-objects-and-property-values-from-expression-trees.aspx
                string lText = ( aExpression.Compile()() ) as string;

                System.Diagnostics.Debug.Assert(
                    !string.IsNullOrEmpty( lText ),
                    string.Format( "{0} não pode ser nulo ou vazio.", lBody.Member.Name )
                );
#endif
            }

            public static void IsAssignableFrom<T>( Type aType, Expression<Func<T>> aExpression )
            {
#if DEBUG
                MemberExpression lBody = ( (MemberExpression)aExpression.Body );
                //Referência: http://blogs.msdn.com/b/csharpfaq/archive/2010/03/11/how-can-i-get-objects-and-property-values-from-expression-trees.aspx
                Type lType = ( aExpression.Compile()() ) as Type;

                System.Diagnostics.Debug.Assert(
                    aType != null && lType != null && aType.IsAssignableFrom( lType ),
                    string.Format( "Tipo da variavel {0} ({1}) não herda do tipo {2}.", lBody.Member.Name, lType, aType )
                );
#endif
            }

            public static void Equals<TExpression, TValue>( Expression<Func<TExpression>> aExpression, TValue aValue )
            {
#if DEBUG
                MemberExpression lBody = ( (MemberExpression)aExpression.Body );
                //Referência: http://blogs.msdn.com/b/csharpfaq/archive/2010/03/11/how-can-i-get-objects-and-property-values-from-expression-trees.aspx
                TValue lValue = (TValue) Convert.ChangeType( aExpression.Compile()(), typeof( TValue ) );

                System.Diagnostics.Debug.Assert(
                    lValue.Equals( aValue ),
                    string.Format( "Valor de {0}({1}) não condiz com o esperado: {2}.", lBody.Member.Name, lValue, aValue )
                );
#endif
            }
            
            public static void IsSubClassOf<T>( Expression<Func<T>> aExpression, Type aClass )
            {
#if DEBUG
                MemberExpression lBody = ( (MemberExpression)aExpression.Body );
                Type lSubClass = ( aExpression.Compile()() ) as Type;

                System.Diagnostics.Debug.Assert(
                    lSubClass.IsSubclassOf( aClass ),
                    string.Format( "Variavel {0}, de tipo {1}, não é uma subclasse do tipo esperado: {2}.", lBody.Member.Name, lSubClass, aClass )
                );
#endif
            }
        }
    }
}